package com.ponhu.ea2.goodsCenter.bms.api.controller;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.google.common.collect.Lists;
import com.ponhu.ea2.common.basic.model.PagedResult;
import com.ponhu.ea2.common.basic.model.ResponseBean;
import com.ponhu.ea2.dto.*;
import com.ponhu.ea2.enums.ResponseCodeEnum;
import com.ponhu.ea2.query.InventoryDownloadTaskQuery;
import com.ponhu.ea2.query.InventoryInfoQuery;
import com.ponhu.ea2.service.facade.InventoryApiService;
import com.ponhu.ea2.support.exception.BusinessRuntimeException;
import com.ponhu.ea2.vo.*;
import io.netty.util.concurrent.FastThreadLocal;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Method;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.constraints.NotNull;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.ponhu.ea2.enums.ResponseCodeEnum.*;

@Slf4j
@RestController
@RequestMapping("/inventory")
@Api(tags = "货品接口", value = "InventoryController")
public class InventoryController {

    @Autowired
    private FastThreadLocal<String> traceIdLocal;

    @DubboReference(version = "1.0.0", check = false, methods = {
            @Method(name = "batchEditPriceUpload", timeout = 600000),
            @Method(name = "createDownloadTask", timeout = 60000)
    })
    private InventoryApiService inventoryApiService;

    /**
     * 条件查询全部货品列表
     *
     * @return
     */
    @ApiOperation(value = "条件查询全部货品列表")
    @PostMapping("/getAllInventorysByQuery")
    public ResponseBean<PagedResult<PhInventoryListVo>> getAllInventorysByQuery(
            @RequestBody InventoryInfoQuery inventoryInfoQuery) {

        return ResponseBean.ok(inventoryApiService.getAllInventorysByQuery(inventoryInfoQuery));
    }

    /**
     * 根据货品ID查询货品详情
     *
     * @return
     */
    @ApiOperation(value = "根据货品ID查询货品详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inventoryId", value = "货品ID",
                    dataType = "long", paramType = "query", required = true),
            @ApiImplicitParam(name = "type", value = "1-详情显示，2-编辑回显",
                    dataType = "int", paramType = "query", required = true)
    })
    @GetMapping("/getInventoryDetailById")
    public ResponseBean<PhInventoryDetailVo> getInventoryDetailById(
            @RequestParam(value = "inventoryId") Long inventoryId,
            @RequestParam(value = "type") Integer type) {

        return ResponseBean.ok(inventoryApiService.getInventoryDetailById(inventoryId, type));
    }

    /**
     * 根据货品编码查询货品详情
     *
     * @param inventoryCode
     * @return
     */
    @ApiOperation(value = "根据货品编码查询货品详情")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inventoryCode", value = "货品编码",
                    dataType = "string", paramType = "query", required = true)
    })
    @GetMapping("/getInventoryDetailByCode")
    public ResponseBean<PhInventoryDetailVo> getInventoryDetailByCode(
            @RequestParam(value = "inventoryCode") @NotNull(message = "货品编码不能为空") String inventoryCode) {
        return ResponseBean.ok(inventoryApiService.getInventoryDetailByCode(inventoryCode));
    }

    /**
     * 根据货品ID查询货品库存状态
     *
     * @return
     */
    @ApiOperation(value = "根据货品ID查询货品库存状态")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inventoryId", value = "货品ID",
                    dataType = "long", paramType = "query", required = true)
    })
    @GetMapping("/getInventoryStockByCode")
    public ResponseBean<Integer> getInventoryStockByCode(
            @RequestParam(value = "inventoryId") Long inventoryId) {

        return ResponseBean.ok(inventoryApiService.getInventoryStockByCode(inventoryId));
    }


    /**
     * 设置货品关联物料
     *
     * @return
     */
    @ApiOperation(value = "设置货品关联物料")
    @PostMapping("/setInventoryMaterial")
    public ResponseBean<Boolean> setInventoryMaterial(
            @RequestBody @Validated InventoryMaterialSetDto inventoryMaterialSetDto) {

        return ResponseBean.ok(inventoryApiService.setInventoryMaterial(inventoryMaterialSetDto));
    }

    /**
     * 编辑货品相关信息(附件、配件、属性)
     *
     * @return
     */
    @ApiOperation(value = " 编辑货品相关信息(附件、配件、属性)")
    @PostMapping("/editPhInventory")
    public ResponseBean<Boolean> editPhInventory(
            @RequestBody @Validated PhInventoryDetailEditDto phInventoryDetailEditDto) {

        return ResponseBean.ok(inventoryApiService.editPhInventory(phInventoryDetailEditDto));
    }

    /**
     * 编辑货品相关商品信息
     *
     * @return
     */
    @ApiOperation(value = " 编辑货品相关商品信息")
    @PostMapping("/editInventoryGoods")
    public ResponseBean<Boolean> editInventoryGoods(
            @RequestBody @Validated PhInventoryGoodsEditDto editDto) {

        // 货品成本(inventoryCost) <= 入库价(warehousePrice) <= 含税供货价(supplyTaxPrice) <= 含税销售价(saleTaxPrice)
        BigDecimal inventoryCost = editDto.getInventoryCost();
        BigDecimal warehousePrice = editDto.getWarehousePrice();
        BigDecimal supplyTaxPrice = editDto.getSupplyTaxPrice();
        BigDecimal saleTaxPrice = editDto.getSaleTaxPrice();
        if (inventoryCost.compareTo(warehousePrice) > 0 ||
                warehousePrice.compareTo(supplyTaxPrice) > 0 ||
                supplyTaxPrice.compareTo(saleTaxPrice) > 0) { // 相关价格校验失败
            throw new BusinessRuntimeException(ResponseCodeEnum
                    .INVENTORY_EDIT_EXCEPTION_800207);
        }

        return ResponseBean.ok(inventoryApiService.editInventoryGoods(editDto));
    }

    /**
     * 同步货品中检结果
     *
     * @return
     */
    @ApiOperation(value = "同步货品中检结果")
    @PostMapping("/syncInventoryAppraisal")
    public ResponseBean<Boolean> syncInventoryAppraisal(
            @RequestBody @Validated PhInventoryAppraisalDto phInventoryAppraisalDto) {

        return ResponseBean.ok(inventoryApiService.syncInventoryAppraisal(phInventoryAppraisalDto));
    }

    /**
     * 根据货品编码获取中检溯源码信息
     *
     * @return
     */
    @ApiOperation(value = "根据货品编码获取中检溯源码信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "inventoryCode", value = "货品编码",
                    dataType = "string", paramType = "query", required = true)
    })
    @GetMapping("/getSourceCodeByCode")
    public ResponseBean<PhInventoryAppraisalVo> getSourceCodeByCode(
            @RequestParam(value = "inventoryCode") String inventoryCode) {

        return ResponseBean.ok(inventoryApiService.getSourceCodeByCode(inventoryCode));
    }

    /**
     * 查询所有的首次编辑人
     */
    @ApiOperation(value = "查询所有的首次编辑人")
    @GetMapping("/getPhInventoryEditName")
    public ResponseBean<List<PhInventoryEditorVo>> getPhInventoryEditName() {
        return ResponseBean.ok(inventoryApiService.getPhInventoryEditName());
    }

    /**
     * 获取货品条形码数据
     *
     * @param code
     * @return
     */
    @ApiImplicitParams({
            @ApiImplicitParam(name = "code", value = "货品编码",
                    dataType = "String", required = true)
    })
    @ApiOperation("获取货品条形码数据")
    @GetMapping("/getInventorBarCodeInfo")
    public ResponseBean getInventorBarCodeInfo(@RequestParam(value = "code") String code) {
        return ResponseBean.ok(inventoryApiService.getInventorBarCodeInfo(code));
    }

    /**
     * 批量改价：校验用户权限
     */
    @ApiOperation(value = "批量改价：校验用户权限")
    @PostMapping("/batchEditPrice/auth")
    public ResponseBean batchEditPriceAuth() {

        return ResponseBean.ok();
    }

    /**
     * 批量改价：下载改价模板
     *
     * @param response
     */
    @ApiOperation(value = "批量改价：下载改价模板")
    @PostMapping("/batchEditPrice/down")
    public void batchEditPriceDown(HttpServletResponse response) {
        BufferedReader br = null;
        OutputStream output = null;
        try {
            output = response.getOutputStream();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/msexcel");
            String fileName = URLEncoder.encode("货品批量改价模板", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            EasyExcelFactory.write(output, InventoryBatchEditPriceVo.class)
                    .sheet("货品价格编辑列表")
                    .doWrite(Arrays.asList(new InventoryBatchEditPriceVo()));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 批量改价：上传改价文件
     *
     * @param uploadFile
     * @param operatorId
     * @param operatorName
     * @return
     */
    @ApiOperation(value = "批量改价：上传改价文件")
    @PostMapping("/batchEditPrice/upload")
    public ResponseBean<InventoryBatchEditResVo> batchEditPriceUpload(@RequestBody MultipartFile uploadFile,
                                                                      @RequestParam("operatorId") Long operatorId,
                                                                      @RequestParam("operatorName") String operatorName) {
        List<InventoryBatchEditPriceVo> editPriceVoList = Lists.newArrayList();
        try {
            EasyExcel.read(uploadFile.getInputStream(), InventoryBatchEditPriceVo.class,
                    new AnalysisEventListener<InventoryBatchEditPriceVo>() {
                        private AtomicInteger index = new AtomicInteger(0);

                        @Override
                        public void invoke(InventoryBatchEditPriceVo editPriceVo, AnalysisContext analysisContext) {
                            editPriceVo.setIndex(index.incrementAndGet());
                            editPriceVoList.add(editPriceVo);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                            log.info("批量改价：上传改价文件 ===>> 解析完成 ===>> {}条", editPriceVoList.size());
                        }
                    }).sheet(0).doRead();
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessRuntimeException(INVENTORY_BATCH_EDIT_EXCEPTION_800218);
        }

        if (editPriceVoList.size() > 500)
            throw new BusinessRuntimeException(INVENTORY_BATCH_EDIT_EXCEPTION_800219);

        OperatorDto operatorDto = new OperatorDto().setOperatorId(operatorId).setOperatorName(operatorName);
        return ResponseBean.ok(inventoryApiService.batchEditPriceUpload(editPriceVoList, operatorDto));
    }

    /**
     * 批量修改备注：校验用户权限
     */
    @ApiOperation(value = "批量修改备注：校验用户权限")
    @PostMapping("/batchEditRemarks/auth")
    public ResponseBean batchEditRemarksAuth() {

        return ResponseBean.ok();
    }

    /**
     * 批量修改备注：下载修改备注模板
     *
     * @param response
     */
    @ApiOperation(value = "批量修改备注：下载修改备注模板")
    @PostMapping("/batchEditRemarks/down")
    public void batchEditRemarksDown(HttpServletResponse response) {
        BufferedReader br = null;
        OutputStream output = null;
        try {
            output = response.getOutputStream();
            response.setCharacterEncoding("utf-8");
            response.setContentType("application/msexcel");
            String fileName = URLEncoder.encode("货品批量修改备注模板", "UTF-8");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");

            EasyExcelFactory.write(output, InventoryBatchEditRemarksVo.class)
                    .sheet("货品备注编辑列表")
                    .doWrite(Arrays.asList(new InventoryBatchEditRemarksVo()));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (output != null) {
                try {
                    output.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 批量修改备注：上传修改备注文件：type=1 追加，type=2 覆盖，type=3 删除
     *
     * @param uploadFile
     * @param operatorId
     * @param operatorName
     * @return
     */
    @ApiOperation(value = "批量修改备注：上传修改备注文件：type=1 追加，type=2 覆盖，type=3 删除")
    @PostMapping("/batchEditRemarks/upload/{type}")
    public ResponseBean<InventoryBatchEditResVo> batchEditRemarksUpload(@RequestBody MultipartFile uploadFile,
                                                                        @PathVariable("type") int type,
                                                                        @RequestParam("operatorId") Long operatorId,
                                                                        @RequestParam("operatorName") String operatorName) {
        List<InventoryBatchEditRemarksVo> editRemarksVoList = Lists.newArrayList();
        try {
            EasyExcel.read(uploadFile.getInputStream(), InventoryBatchEditRemarksVo.class,
                    new AnalysisEventListener<InventoryBatchEditRemarksVo>() {
                        private AtomicInteger index = new AtomicInteger(0);

                        @Override
                        public void invoke(InventoryBatchEditRemarksVo editPriceVo, AnalysisContext analysisContext) {
                            editPriceVo.setIndex(index.incrementAndGet());
                            editRemarksVoList.add(editPriceVo);
                        }

                        @Override
                        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                            log.info("批量修改备注：上传修改备注文件 ===>> 解析完成 ===>> {}条", editRemarksVoList.size());
                        }
                    }).sheet(0).doRead();
        } catch (Exception e) {
            e.printStackTrace();
            throw new BusinessRuntimeException(INVENTORY_BATCH_EDIT_EXCEPTION_800218);
        }

        if (editRemarksVoList.size() > 500)
            throw new BusinessRuntimeException(INVENTORY_BATCH_EDIT_EXCEPTION_800219);

        OperatorDto operatorDto = new OperatorDto().setOperatorId(operatorId).setOperatorName(operatorName);
        return ResponseBean.ok(inventoryApiService.batchEditRemarksUpload(editRemarksVoList, type, operatorDto));
    }

    /**
     * 下载工具：新建下载任务
     *
     * @param uploadFile
     * @param operatorId
     * @param operatorName
     * @return
     */
    @ApiOperation(value = "下载工具：新建下载任务")
    @PostMapping("/createDownloadTask")
    public ResponseBean<InventoryDownLoadResVo> createDownloadTask(@RequestBody MultipartFile uploadFile,
                                                                   @RequestParam(value = "operatorId") Long operatorId,
                                                                   @RequestParam(value = "operatorName") String operatorName) {
        BufferedReader br = null;
        try {
            Reader reader = new InputStreamReader(uploadFile.getInputStream());
            br = new BufferedReader(reader);
            List<String> inventoryCodeList = Lists.newArrayList();
            String inventoryCode;
            while ((inventoryCode = br.readLine()) != null) {
                inventoryCodeList.add(inventoryCode.trim());
            }
            Integer uploadNum = inventoryCodeList.size();

            if (CollectionUtils.isEmpty(inventoryCodeList))
                throw new BusinessRuntimeException(PARAMETER_IS_INCORRECT_800001);
            if (inventoryCodeList.size() > 100)
                throw new BusinessRuntimeException(INVENTORY_DOWNLOAD_TOOLS_EXCEPTION_800222);

            List<InventoryDownLoadFailVo> failVoList = Lists.newArrayList();
            inventoryCodeList = inventoryCodeList.stream().collect(Collectors.groupingBy(Function.identity()))
                    .values().stream().map(list -> {
                        for (int i = 1; i < list.size(); i++) {
                            InventoryDownLoadFailVo failVo = new InventoryDownLoadFailVo()
                                    .setInventoryCode(list.get(0)).setMsg("货品编码重复");
                            failVoList.add(failVo);
                        }
                        return list.get(0);
                    }).collect(Collectors.toList());

            OperatorDto operatorDto = new OperatorDto().setOperatorId(operatorId).setOperatorName(operatorName);
            failVoList.addAll(inventoryApiService.createDownloadTask(inventoryCodeList, operatorDto));

            InventoryDownLoadResVo downLoadResVo = new InventoryDownLoadResVo()
                    .setSuccessNum(uploadNum - failVoList.size())
                    .setUploadNum(uploadNum)
                    .setFailNum(failVoList.size())
                    .setFailVoList(failVoList);

            return ResponseBean.ok(downLoadResVo);
        } catch (Exception e) {
            e.printStackTrace();
            if (e instanceof BusinessRuntimeException) {
                throw (BusinessRuntimeException) e;
            } else {
                log.error("createDownloadTask ===>>[{}] ===>> 下载工具-新建下载任务 ===>> 程序异常", traceIdLocal.get());
                return ResponseBean.error();
            }
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 下载工具：查询任务列表
     *
     * @return
     */
    @ApiOperation(value = "下载工具：查询任务列表")
    @PostMapping("/getDownloadTaskList")
    public ResponseBean<PagedResult<InventoryDownLoadListVo>> getDownloadTaskList(
            @RequestBody InventoryDownloadTaskQuery taskQuery) {

        return ResponseBean.ok(inventoryApiService.getDownloadTaskList(taskQuery));
    }

}